import json
import pytz
import logging

import requests
import xlwt
import math
import os
import zipfile
import time
import threading
from itertools import groupby
from datetime import datetime, timedelta

from odoo import http, _, SUPERUSER_ID, registry, api
from odoo.http import request, content_disposition
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from odoo.tools.misc import format_date

_logger = logging.getLogger(__name__)


class Controller(http.Controller):

    @http.route('/download/sb/wip/report/excel/<string:report_type>/<docids>', type='http', auth='user', website=True)
    def download_sample_invoice_excel(self, report_type=None, docids=None, **data):
        if docids:
            docids = [int(i) for i in docids.split(',') if i.isdigit()]
        else:
            docids = []
        if report_type == 'development':
            development_ids = request.env['s.research.and.development.order'].browse(docids)
            data = development_ids.get_wip_report_data()
        else:
            sale_ids = request.env['sale.order'].browse(docids)
            data = sale_ids.get_wip_report_data()

        book = xlwt.Workbook(encoding='utf-8')
        sheet = book.add_sheet('Sheet1')

        def create_style(font_height, center=True, borders=True):
            style = xlwt.XFStyle()
            font = xlwt.Font()
            font.height = font_height
            style.font = font
            if center:
                # 垂直居中 水平居中
                vertically_horizontally_centered = xlwt.Alignment()
                vertically_horizontally_centered.vert = xlwt.Alignment.VERT_CENTER
                vertically_horizontally_centered.horz = xlwt.Alignment.HORZ_CENTER
                style.alignment = vertically_horizontally_centered
            if borders:
                border = xlwt.Borders()
                border.bottom = border.top = border.left = border.right = xlwt.Borders.THIN
                style.borders = border
            return style

        field_style = create_style(15 * 15, center=True)
        for i, item in enumerate(data):
            sheet.row(i).height_mismatch = True
            sheet.row(i).height = 300
            for index, v in enumerate(item):
                sheet.write(i, index, v, field_style)

        sheet.col(0).width = 256 * 20
        sheet.col(1).width = 256 * 40
        if report_type == 'development':
            sheet.col(2).width = 256 * 20
            sheet.col(3).width = 256 * 15
        else:
            sheet.col(2).width = 256 * 20
            sheet.col(3).width = 256 * 20
            sheet.col(4).width = 256 * 40

        user_tz = request.env.user.tz or 'UTC'
        timezone = pytz.timezone(user_tz)
        utc_time = pytz.utc.localize(datetime.now())
        local_time = utc_time.astimezone(timezone)
        file_name = f'WIP报表-{local_time.strftime(DEFAULT_SERVER_DATE_FORMAT)}.xls'
        response = request.make_response(None, headers=[
            ('Content-Type', 'application/vnd.ms-excel'),
            ('Content-Disposition', content_disposition(file_name))
        ])
        book.save(response.stream)
        return response

    @http.route('/download/sb/production/wip/report/excel/<string:department>/<string:product_type>', type='http',
                auth='user', website=True)
    def download_production_wip_report_excel(self, department='plan', product_type='all', **data):
        """
        department: 部门
        product_type: 产品 materiel_status 属性， P 代表量产
        """
        if department == 'production':
            data = self.get_wip_report_data_with_production_department(product_type)
        else:
            data = self.get_wip_report_data(product_type)

        book = xlwt.Workbook(encoding='utf-8')
        sheet = book.add_sheet('Sheet1')

        def create_style(font_height, center=True, borders=True):
            style = xlwt.XFStyle()
            font = xlwt.Font()
            font.height = font_height
            style.font = font
            if center:
                # 垂直居中 水平居中
                vertically_horizontally_centered = xlwt.Alignment()
                vertically_horizontally_centered.vert = xlwt.Alignment.VERT_CENTER
                vertically_horizontally_centered.horz = xlwt.Alignment.HORZ_CENTER
                style.alignment = vertically_horizontally_centered
            if borders:
                border = xlwt.Borders()
                border.bottom = border.top = border.left = border.right = xlwt.Borders.THIN
                style.borders = border
            return style

        field_style = create_style(15 * 15, center=True)
        for i, item in enumerate(data):
            sheet.row(i).height_mismatch = True
            sheet.row(i).height = 300
            for index, v in enumerate(item):
                sheet.write(i, index, v, field_style)

        if department == 'production':
            sheet.col(0).width = 256 * 30
            sheet.col(1).width = 256 * 30
            sheet.col(2).width = 256 * 20
            sheet.col(3).width = 256 * 30
            sheet.col(4).width = 256 * 20
            sheet.col(5).width = 256 * 13
            sheet.col(6).width = 256 * 13
            sheet.col(7).width = 256 * 12
            sheet.col(8).width = 256 * 12
            sheet.col(9).width = 256 * 12
            sheet.col(10).width = 256 * 12
        else:
            sheet.col(0).width = 256 * 12
            sheet.col(1).width = 256 * 20
            sheet.col(2).width = 256 * 20
            sheet.col(3).width = 256 * 30
            sheet.col(4).width = 256 * 10
            sheet.col(5).width = 256 * 13

            sheet.col(7).width = 256 * 12
            sheet.col(8).width = 256 * 12
            sheet.col(9).width = 256 * 12
            sheet.col(10).width = 256 * 12
            sheet.col(11).width = 256 * 12
            sheet.col(12).width = 256 * 12

        user_tz = request.env.user.tz or 'UTC'
        timezone = pytz.timezone(user_tz)
        utc_time = pytz.utc.localize(datetime.now())
        local_time = utc_time.astimezone(timezone)
        file_name = f'WIP报表-{local_time.strftime(DEFAULT_SERVER_DATE_FORMAT)}.xls'
        response = request.make_response(None, headers=[
            ('Content-Type', 'application/vnd.ms-excel'),
            ('Content-Disposition', content_disposition(file_name))
        ])
        book.save(response.stream)
        return response

    def get_wip_report_data_with_production_department(self, product_type='all'):
        data = [[
            _('Lot Name'), _('Product'), _('Online station'), _('Online process'), _('plan delivery'),
            _('Sale Order Qty'), _('Stay time (hours)'), _('WIP(PCS)'), _('WIP(SET)'),
            _('WIP(PNL)'), _('Area PNL(㎡)')
        ]]
        domain = []
        if product_type == 'sample':
            domain = [('product_id.materiel_status', '!=', 'P')]
        elif product_type == 'mass':
            domain = [('product_id.materiel_status', '=', 'P')]

        for line in request.env['mrp.workorder.sum'].sudo().search(domain).sorted(lambda x: x.work_station_id.sequence):
            if not line.production_id:
                continue
            sources = line.production_id
            planned_receiving_date = ''
            order_qty = 0
            while True:
                sale_line_ids = sources.mapped('s_sale_order_line_ids')
                rd_line_ids = sources.mapped('s_development_line_ids')
                if sale_line_ids:
                    planned_receiving_date = sale_line_ids[0].s_planned_receiving_date
                    order_qty = sum(sale_line_ids.mapped('product_uom_qty'))
                    break
                elif rd_line_ids:
                    planned_receiving_date = rd_line_ids[0].order_id.planned_receiving_date
                    order_qty = sum(rd_line_ids.mapped('product_qty'))
                    break
                sources = sources._get_sources()
                if not sources:
                    break
                else:
                    sources = sources[0]
            work_order_ids = line.production_id.workorder_ids.filtered(lambda x: x.state != 'done').sorted('step')
            if work_order_ids:
                center = work_order_ids[0].workcenter_id.display_name
                stop_time = work_order_ids[0].s_stop_time
            else:
                center = ''
                stop_time = 0
            data.append([
                line.production_id.name,
                line.product_id.name,
                line.work_station_id.name,
                center,
                planned_receiving_date and f'{format_date(request.env, planned_receiving_date)}' or '',
                order_qty,
                int(stop_time),
                line.qty_wip or 0,
                line.qty_wip_set or 0,
                line.qty_wip_pnl or 0,
                round(line.qty_wip_seta, 3) or 0,
            ])
        return data

    def get_wip_report_data(self, product_type='all'):
        """ 获取生产WIP报表数据 """
        data = []
        station_ids = request.env['work.station'].search([('disuse', '=', False)])
        label_list = self._get_label_list(station_ids)
        data.append(label_list)
        domain = [('state', 'not in', ('done', 'cancel')), ('mo_type', '!=', 'W')]
        if product_type == 'sample':
            domain.append(('product_id.materiel_status', '!=', 'P'))
        elif product_type == 'mass':
            domain.append(('product_id.materiel_status', '=', 'P'))
        production_ids = request.env['mrp.production'].search(domain)

        sale_production_ids = production_ids.filtered(lambda p: p.s_sale_order_line_ids)
        data.extend(self._get_sale_data(sale_production_ids, station_ids))

        development_production_ids = production_ids.filtered(lambda p: p.s_development_line_ids)
        data.extend(self._get_development_data(development_production_ids, station_ids))
        return data

    def _get_sale_data(self, sale_production_ids, station_ids):
        def by_sale_line(production):
            line_list = production.mapped('s_sale_order_line_ids.id')
            line_list.sort()
            return line_list

        data = []
        sale_production_ids = sale_production_ids.sorted(key=by_sale_line)
        for sale_line_ids, g in groupby(sale_production_ids, key=lambda x: x.s_sale_order_line_ids):
            station_balance_vals = {}
            child_production_ids = request.env['mrp.production']
            p_ids = request.env['mrp.production'].concat(*g)
            p_ids |= sale_line_ids.s_mrp_production_ids
            p_ids = p_ids.filtered(lambda x: x.state != 'cancel')
            done_production_ids = p_ids.filtered(lambda x: x.state == 'done')
            production_ids = p_ids - done_production_ids

            panel_uom_value = p_ids[0].s_value_pnl

            production_total = sum(p_ids.mapped('product_uom_qty'))  # 生产单总数量
            production_panel_total = sum(p_ids.mapped('panel_uom_qty'))  # 生产单总数量（PANEL）
            temporary_panel_qty = 0
            # 入库总数量
            inventory_total = sum(done_production_ids.mapped('qty_produced')) - sum(
                done_production_ids.mapped('qty_reject'))

            for p in production_ids:
                child_production_ids |= p._get_all_child()

            # 获取制造单和下级制造单的数量
            for station in station_ids:
                workorder_ids = production_ids.mapped('workorder_ids').filtered(lambda x: x.work_station_id == station)
                if not workorder_ids:
                    continue
                # 从FQC开始 以 PCS单位计算
                station_balance_vals[station] = {
                    'PCS': sum(workorder_ids.mapped('qty_wip')),
                    'PANEL': sum(workorder_ids.mapped('qty_wip_pnl')),
                    'symbol': '+' if workorder_ids.filtered(lambda x: x.state not in ('done', 'cancel')) else '-'
                }

            line = request.env['sale.order.line']
            for line in sale_line_ids:
                # if not float_compare(line.product_uom_qty, line.qty_delivered, precision_rounding=line.product_uom.rounding) == 1:
                #     continue
                need_qty = line.s_planned_qty  # 投料数量
                # 计算投料PANEL数量
                if line == sale_line_ids[-1]:
                    plan_pnl_qty = production_panel_total - temporary_panel_qty
                else:
                    plan_pnl_qty = math.ceil(need_qty / panel_uom_value) if panel_uom_value else 0  # 投料PNL数量
                    temporary_panel_qty += plan_pnl_qty
                line_inventory_qty = min([inventory_total, need_qty])

                s_list = [
                    line.s_partner_id.code,
                    line.order_id.name,
                    line.pn,
                    line.product_id.name,
                    '',
                    self._convert_the_current_time_zone(p_ids[0].create_date),
                    self._convert_the_current_time_zone(line.s_planned_receiving_date),
                    dict(line.order_id.fields_get(allfields=['order_type'])['order_type']['selection'])[
                        line.order_id.order_type] if line.order_id.order_type else '',
                    line.product_uom_qty,  # 销售订单数量
                    plan_pnl_qty,  # 投料PNL数量
                    need_qty,  # 投料数量
                    0,  # 在线PANEL  下面会计算 ，占位
                    line_inventory_qty,
                    0  # 有效PCS数 下面会计算 ，占位
                ]
                production_total -= need_qty
                inventory_total -= line_inventory_qty
                line_qty_producing = 0  # 在线PANEL数
                effective_qty = 0  # 有效PCS数

                for station in station_ids:
                    if station not in station_balance_vals:
                        s_list.append('')
                        continue

                    qty_wip_dict = station_balance_vals[station]  # qty_wip 是字典类型
                    pcs_qty = qty_wip_dict.get('PCS', 0)
                    symbol = qty_wip_dict.get('symbol', '')
                    panel_qty = qty_wip_dict.get('PANEL', 0)
                    # 最后一条分配剩下的所有数量
                    if line == sale_line_ids[-1]:

                        if station.code and station.code in ('FQC', 'FQA', 'PKG'):
                            s_list.append(pcs_qty or symbol)
                        else:
                            s_list.append(panel_qty or symbol)
                        effective_qty += pcs_qty
                        line_qty_producing += panel_qty
                        # station_balance_vals.pop(station)
                    else:
                        min_qty = min([pcs_qty, line.s_planned_qty])
                        station_balance_vals[station]['PCS'] -= min_qty

                        min_panel = min([panel_qty, plan_pnl_qty])
                        station_balance_vals[station]['PANEL'] -= min_panel

                        if station.code and station.code in ('FQC', 'FQA', 'PKG'):
                            s_list.append(min_qty or symbol)
                        else:
                            s_list.append(min_panel or symbol)

                        effective_qty += pcs_qty
                        line_qty_producing += min_panel

                s_list[11] = line_qty_producing
                s_list[13] = effective_qty
                # 在线有效pcs数为0，清空
                if effective_qty == 0:
                    s_list[14:] = [''] * (len(s_list) - 13)
                data.append(s_list)

            data.extend(self._get_child_data(
                child_production_ids,
                station_ids,
                line.s_partner_id.code,
                line.order_id.name,
                line.pn,
                '',
                self._convert_the_current_time_zone(line.s_planned_receiving_date),
                dict(line.order_id.fields_get(allfields=['order_type'])['order_type']['selection'])[
                    line.order_id.order_type] if line.order_id.order_type else '',
                line.product_uom_qty,  # 销售订单数量
            ))

        return data

    def _get_development_data(self, development_production_ids, station_ids):
        data = []
        for development_line_ids, g in groupby(
                development_production_ids.sorted(key=lambda p: p.s_development_line_ids),
                key=lambda p: p.s_development_line_ids):
            station_balance_vals = {}
            child_production_ids = request.env['mrp.production']
            p_ids = request.env['mrp.production'].concat(*g)
            p_ids |= development_line_ids.mrp_production_ids
            p_ids = p_ids.filtered(lambda x: x.state != 'cancel')
            done_production_ids = p_ids.filtered(lambda x: x.state == 'done')
            production_ids = p_ids - done_production_ids

            production_total = sum(p_ids.mapped('product_uom_qty'))  # 生产单总数量
            production_panel_total = sum(p_ids.mapped('panel_uom_qty'))  # 生产单总数量（PANEL）
            temporary_panel_qty = 0

            panel_uom_value = p_ids[0].s_value_pnl

            # 入库总数量
            inventory_total = sum(done_production_ids.mapped('qty_produced')) - sum(
                done_production_ids.mapped('qty_reject'))

            for p in p_ids:
                child_production_ids |= p._get_all_child()

            for station in station_ids:
                workorder_ids = production_ids.mapped('workorder_ids').filtered(lambda x: x.work_station_id == station)
                if not workorder_ids:
                    continue
                # 从FQC开始 以 PCS单位计算
                station_balance_vals[station] = {
                    'PCS': sum(workorder_ids.mapped('qty_wip')),
                    'PANEL': sum(workorder_ids.mapped('qty_wip_pnl'))
                }

            line = request.env['s.research.and.development.order.line']
            for line in development_line_ids:
                need_qty = line.planned_qty  # 投料数量
                if line == development_line_ids[-1]:
                    plan_pnl_qty = production_panel_total - temporary_panel_qty
                else:
                    plan_pnl_qty = math.ceil(need_qty / panel_uom_value) if panel_uom_value else 0  # 投料PNL数量
                    temporary_panel_qty += plan_pnl_qty
                line_inventory_qty = min([inventory_total, need_qty])
                inventory_total -= line_inventory_qty
                s_list = [
                    '',
                    line.order_id.name,
                    '',
                    line.product_id.name,
                    '',
                    self._convert_the_current_time_zone(p_ids[0].create_date),
                    self._convert_the_current_time_zone(line.order_id.planned_receiving_date),
                    '研发单',
                    line.product_qty,
                    plan_pnl_qty,  # 投料PNL数量
                    need_qty,  # 投料数量
                    0,
                    line_inventory_qty,
                    0
                ]

                line_qty_producing = 0
                effective_qty = 0  # 有效PCS数
                symbol = '-'
                for station in station_ids:
                    if station not in station_balance_vals:
                        s_list.append('')
                        continue

                    qty_wip_dict = station_balance_vals[station]  # qty_wip 是字典类型
                    pcs_qty = qty_wip_dict.get('PCS', 0)
                    panel_qty = qty_wip_dict.get('PANEL', 0)
                    if pcs_qty > 0:
                        symbol = '+'

                    # 最后一条分配剩下的所有数量
                    if line == development_line_ids[-1]:

                        if station.code and station.code in ('FQC', 'FQA', 'PKG'):
                            s_list.append(pcs_qty or symbol)
                        else:
                            s_list.append(panel_qty or symbol)
                        effective_qty += pcs_qty
                        line_qty_producing += panel_qty
                    else:
                        min_qty = min([pcs_qty, line.s_planned_qty])
                        station_balance_vals[station]['PCS'] -= min_qty

                        min_panel = min([panel_qty, plan_pnl_qty])
                        station_balance_vals[station]['PANEL'] -= min_panel

                        if station.code and station.code in ('FQC', 'FQA', 'PKG'):
                            s_list.append(min_qty or symbol)
                        else:
                            s_list.append(min_panel or symbol)

                        effective_qty += pcs_qty
                        line_qty_producing += min_panel

                s_list[11] = line_qty_producing
                s_list[13] = effective_qty
                if effective_qty == 0:
                    s_list[14:] = [''] * (len(s_list) - 13)
                data.append(s_list)

            data.extend(self._get_child_data(
                child_production_ids,
                station_ids,
                '',
                line.order_id.name if line else '',
                '',
                '',
                self._convert_the_current_time_zone(line.order_id.planned_receiving_date) if line else '',
                '研发单',
                line.product_qty if line else '',
            ))

        return data

    def _get_child_data(
            self,
            child_production_ids,
            station_ids,
            partner_name=None,
            sale_name=None,
            pn=None,
            delivery_info=None,
            scheduled_date=None,
            order_type=None,
            order_qty=None
    ):
        data = []
        child_production_ids = child_production_ids.filtered(lambda x: x.state not in ('done', 'to_close', 'cancel'))
        for product_id, p in groupby(child_production_ids.sorted(key=lambda p: p.product_id.id),
                                     key=lambda p: p.product_id):
            station_balance_vals = {}
            child_p_ids = request.env['mrp.production'].concat(*p)
            panel_uom_value = child_p_ids[0].s_value_pnl

            done_production_ids = child_p_ids.filtered(lambda x: x.state == 'done')
            production_ids = child_p_ids - done_production_ids
            for station in station_ids:
                workorder_ids = production_ids.mapped('workorder_ids').filtered(lambda x: x.work_station_id == station)
                if not workorder_ids:
                    continue
                # 从FQC开始 以 PCS单位计算
                station_balance_vals[station] = {
                    'PCS': sum(workorder_ids.mapped('qty_wip')),
                    'PANEL': sum(workorder_ids.mapped('qty_wip_pnl'))
                }
            # 入库总数量
            inventory_total = sum(done_production_ids.mapped('qty_produced')) - sum(
                done_production_ids.mapped('qty_reject'))
            # 在线总数量
            # online_total = sum(production_ids.filtered(lambda x: x.state == 'progress').mapped('qty_producing')) / panel_uom_value
            child_list = [
                partner_name or '',
                sale_name or '',
                pn or '',
                product_id.name,
                delivery_info or '',
                self._convert_the_current_time_zone(child_p_ids[0].create_date),
                scheduled_date or '',
                order_type or '',
                order_qty or '',  # 销售订单数量
                sum(child_p_ids.mapped('panel_uom_qty')),  # 投料PNL数量
                sum(child_p_ids.mapped('product_qty')),  # 投料数量
                0,
                inventory_total,
                0,
            ]

            line_qty_producing = 0  # 在线pnl数量
            effective_qty = 0  # 有效PCS数
            symbol = '-'
            for station in station_ids:
                if station not in station_balance_vals:
                    child_list.append('')
                    continue

                qty_wip_dict = station_balance_vals[station]  # qty_wip 是字典类型
                pcs_qty = qty_wip_dict.get('PCS', 0)
                panel_qty = qty_wip_dict.get('PANEL', 0)
                if pcs_qty > 0:
                    symbol = '+'

                if station.code and station.code in ('FQC', 'FQA', 'PKG'):
                    child_list.append(pcs_qty or symbol)
                else:
                    child_list.append(panel_qty or symbol)
                effective_qty += pcs_qty
                line_qty_producing += panel_qty

            # 确保在线PNL数不小于0
            line_qty_producing = max(line_qty_producing, 0)
            child_list[11] = line_qty_producing
            child_list[13] = effective_qty
            if effective_qty == 0:
                child_list[14:] = [''] * (len(child_list) - 13)
            data.append(child_list)
        return data

    def _get_label_list(self, station_ids):
        # label_list = [
        #     '客户', '销售单号', '客户型号', '产品', '交货信息', '计划交期', '类别', '订单数量', '投料PNL数量', '投料数量',
        #     '在线PNL数量', '入库PCS数量', '有效PCS数'
        # ]
        label_list = [
            _('customer'), _('Sale Order'), _('CUSTOMER PART NO'), _('Product'), _('Delivery information'),
            _('Feeding date'), _('Planned delivery date'), _('Order Type'), _('Order quantity'),
            _('Quantity of feeding(PNL)'), _('Quantity of feeding(PCS)'), _('Online quantity(PNL)'),
            _('Inventory quantity(PCS)'), _('Quantity of good products(PCS)')
        ]
        for name, eng in zip(station_ids.mapped('name'), station_ids.mapped('name_eng')):
            label_list.append('/'.join([name, eng]))

        return label_list

    def _convert_the_current_time_zone(self, date):
        if not date:
            return ''
        user_tz = request.env.user.tz or 'UTC'
        timezone = pytz.timezone(user_tz)

        # 将 UTC 时间转换为用户的本地时区时间
        utc_time = pytz.utc.localize(date)
        local_time = utc_time.astimezone(timezone)
        return local_time.strftime(DEFAULT_SERVER_DATE_FORMAT)

    @http.route(['/download/sb/production/report', '/download/sb/production/report/pan'], type='http', auth='user',
                methods=['POST', 'GET'], csrf=False)
    def download_sb_production_report(self, **kwargs):
        try:
            product_id = int(kwargs.get('product_id'))
        except ValueError:
            return http.Response({'code': 400, 'msg': 'product_id is not a number'})
        product_ids = [product_id]
        # 获取成品下的半成品
        product = request.env['product.template'].browse(product_id)
        finished_categ = request.env.ref('sb_sale.finished_product_type').id
        semi_categ = request.env.ref('sb_sale.semi_product_type').id
        c = request.env['product.category'].sudo().search([('code', '=', 'OPFP')])
        c |= c.child_id
        category_ids = [finished_categ, semi_categ]
        category_ids.extend(c.ids)
        if product.categ_id.id not in category_ids:
            return http.Response({'code': 400, 'msg': 'product is not a finished product or semi product'})
        # 递归获取内层半成品
        product_ids.extend(self.get_child_semi_product_ids(product.bom_ids))
        # 判断文件路径是否存在
        filepath = os.path.abspath(os.path.dirname(__file__)) + '/' + product.name
        if os.path.exists(filepath):
            # 文件存在, 需要将里面的文件删除
            del_list = os.listdir(filepath)
            for f in del_list:
                file_path = os.path.join(filepath, f)
                if os.path.isfile(file_path):
                    os.remove(file_path)
        else:
            os.makedirs(filepath)
            os.chmod(filepath, mode=0o777)
        for product_id in product_ids:
            thread1 = threading.Thread(target=self.fetch_data, args=(product_id, filepath))
            thread1.start()
        product_name_list = request.env['product.template'].browse(product_ids).mapped('name')
        new_product_name = []
        flag_list = []
        index = 0
        while True:
            for product_name in product_name_list:
                if '/' in product_name:
                    product_name = product_name.replace('/', '_')
                path = filepath + '/' + product_name + '.pdf'
                r = os.path.exists(path)
                if r and product_name not in new_product_name:
                    new_product_name.append(product_name)
                    flag_list.append(r)
            if len(flag_list) == len(product_name_list):
                break
            index += 1
            if index > 50:  # 一般不超过50秒, 如果超过50秒, 则下载失败
                return json.dumps({'code': 400, 'msg': '下载超时'})
            time.sleep(1)
        zip_file_name = f'{product.name}.zip'
        zip_file = filepath + '/' + zip_file_name
        zip = zipfile.ZipFile(zip_file, "w", zipfile.ZIP_DEFLATED)
        for path, dirnames, filenames in os.walk(filepath):
            filenames.remove(zip_file_name)
            fpath = path.replace(filepath, '')
            for filename in filenames:
                zip.write(os.path.join(path, filename), os.path.join(fpath, filename))
        zip.close()
        with open(zip_file, 'rb') as f:
            zip_data = f.read()
        record_data = {
            'doc_type': 'jmi-sale-return',
            'api_params': json.dumps(kwargs),
            'api_route': '/download/sb/production/report/pan',
            'state': 'success'
        }

        if request.httprequest.path == '/download/sb/production/report':
            pdfhttpheaders = [('Content-Type', 'application/octet-stream'), ('Content-Length', len(zip_data))]
            response = request.make_response(zip_data, headers=pdfhttpheaders)
            response.headers.add('Content-Disposition', content_disposition(zip_file_name))
        else:
            # url = 'http://192.168.1.4:5000/FileSharing/JMI'
            url = request.env['ir.config_parameter'].sudo().get_param('jmi.upload.zip', 'http://10.150.191.2:5000/FileSharing/JMI')
            f = open(zip_file, 'rb')
            files = {'file': f}
            response = json.dumps({'code': 200, 'msg': '下载成功'})
            try:
                res = requests.post(url, files=files)
                if res.status_code != 200:
                    record_data['state'] = 'fail'
                    record_data['result_json'] = res.text
                    response = json.dumps({'code': 400, 'msg': '上传失败'})
                else:
                    record_data['result_json'] = res.text
                    response = json.dumps({'code': 200, 'msg': '下载成功', 'data': res.text})
                f.close()
            except Exception as e:
                record_data['state'] = 'fail'
                record_data['result_json'] = str(e)
                response = json.dumps({'code': 400, 'msg': '上传失败'})
            request.env['api.records'].create(record_data)
        # 执行完成后删除所有文件
        del_list = os.listdir(filepath)
        for f in del_list:
            file_path = os.path.join(filepath, f)
            if os.path.isfile(file_path):
                os.remove(file_path)
        return response

    def get_child_semi_product_ids(self, bom_ids):
        semi_categ = request.env.ref('sb_sale.semi_product_type')
        finished_categ = request.env.ref('sb_sale.finished_product_type')
        bom_line = bom_ids.bom_line_ids.filtered(lambda x: x.product_id.categ_id in [semi_categ, finished_categ])
        product_id = bom_line.mapped('product_id.product_tmpl_id')
        product_ids = product_id.ids
        if product_id.bom_ids:
            res = self.get_child_semi_product_ids(product_id.bom_ids)
            product_ids.extend(res)
        return product_ids

    def fetch_data(self, product_id, filepath):

        with registry('WTT_odoo17').cursor() as new_cr:
            env = api.Environment(new_cr, SUPERUSER_ID, {'lang': 'zh_CN', 'uid': SUPERUSER_ID})
            product_id = env['product.template'].browse(product_id)
            report = env['ir.actions.report']
            reportname = f'pcbmanufact.report_product_production_view'
            product_name = product_id.name
            data = {
                'context': {
                    "lang": "zh_CN",
                    "tz": "Asia/Bangkok",
                    "uid": SUPERUSER_ID,
                    "allowed_company_ids": env.companies.ids,
                    "active_id": product_id,
                    "active_ids": product_id.ids,
                    "active_model": "product.template",
                    "active_domain": [["is_finished", "=", True]]
                }
            }
            context = data.get('context')
            if '/' in product_name:
                product_name = product_name.replace('/', '_')
            pdf = report.with_context(context)._render_qweb_pdf(reportname, [product_id.id], data=data)[0]
            fullpath = filepath + '/' + product_name + '.pdf'
            with open(fullpath, 'wb') as f:
                f.write(pdf)
            now = datetime.now() + timedelta(hours=8)
            ts = now.timestamp()
            os.utime(fullpath, (ts, ts))
            os.chmod(fullpath, mode=0o777)  # 增加文件权限

    @http.route('/download/async/report', type='json', auth='public', methods=['POST'], csrf=False, cors='*')
    def download_async_report(self, **kwargs):
        filepath = kwargs.get('filepath')
        product_ids = kwargs.get('product_ids')
        data = kwargs.get('data')
        _logger.info('进入打印接口: %s' % kwargs)
        product = request.env['product.template'].sudo().search([('id', 'in', product_ids)])
        _logger.info('获取到产品: %s' % product.mapped('name'))
        reportname = f'pcbmanufact.report_product_production_view'
        for product_id in product:
            product_name = product_id.name
            if '/' in product_name:
                product_name = product_name.replace('/', '_')
            _logger.info('执行进入打印异步: %s' % product_name)
            product_id.sudo().make_pdf(data, reportname, filepath, product_name)
            _logger.info('完成打印异步')
            os.chmod(filepath, mode=0o777)  # 增加文件权限
        return {'code': 200}
